package com.iotechn.unimall.admin.api.treeOrder;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.iotechn.unimall.admin.api.order.AdminOrderServiceImpl;
import com.iotechn.unimall.biz.service.tree.TreeBizService;
import com.iotechn.unimall.core.exception.AdminServiceException;
import com.iotechn.unimall.core.exception.ExceptionDefinition;
import com.iotechn.unimall.core.exception.ServiceException;
import com.iotechn.unimall.data.component.LockComponent;
import com.iotechn.unimall.data.domain.TreeDetailsDO;
import com.iotechn.unimall.data.domain.TreeOrderDO;
import com.iotechn.unimall.data.domain.TreeDetailOrderDO;
import com.iotechn.unimall.data.domain.UserDO;
import com.iotechn.unimall.data.enums.OrderStatusType;
import com.iotechn.unimall.data.enums.UserLoginType;
import com.iotechn.unimall.data.mapper.TreeDetailsMapper;
import com.iotechn.unimall.data.mapper.TreeDetailsOrderMapper;
import com.iotechn.unimall.data.mapper.TreeOrderMapper;
import com.iotechn.unimall.data.mapper.UserMapper;
import com.iotechn.unimall.data.model.Page;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;


@Service
public class AdminTreeOrderServiceImpl implements AdminTreeOrderService {

    private static final Logger logger = LoggerFactory.getLogger(AdminOrderServiceImpl.class);

    public static final String ORDER_REFUND_LOCK = "TREE_ORDER_REFUND_LOCK_";

    @Value("${com.iotechn.unimall.wx.mini.app-id}")
    private String wxMiNiAppid;
    @Value("${com.iotechn.unimall.wx.app.app-id}")
    private String wxAppAppid;

    @Autowired
    private LockComponent lockComponent;
    @Autowired
    private TreeOrderMapper treeOrderMapper;
    @Autowired
    private TreeDetailsOrderMapper treeOrderDetailsMapper;
    @Autowired
    private TreeDetailsMapper treeDetailsMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private TreeBizService treeBizService;
    @Autowired
    private WxPayService wxPayService;

    @Override
    public Page<TreeOrderDO> list(Integer page, Integer limit, String orderNo,
                                   String channel,String phone,String landNo,
                                   String title,Integer price,Integer status, Long adminId) throws ServiceException {
        List<TreeOrderDO> treeOrderDOS =
                treeOrderMapper.selectDetailList(phone, orderNo, title,
                        landNo, channel, status, (page - 1) * limit, limit);
        Long count = treeOrderMapper.countOrder(phone, orderNo, title, landNo, channel, status);
        return new Page<>(treeOrderDOS, page, limit, count);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String cancel(String orderNo, Long adminId) throws ServiceException {
        List<TreeDetailOrderDO> list = treeOrderDetailsMapper.selectList(
                new EntityWrapper<TreeDetailOrderDO>().setSqlSelect("land_id")
                        .eq("order_no", orderNo));
        if(CollectionUtils.isEmpty(list)){
            throw new AdminServiceException(ExceptionDefinition.ORDER_NOT_EXIST);
        }
        // 回退库存
        for (TreeDetailOrderDO detailsDO : list) {
            TreeDetailsDO treeDetailsDO = new TreeDetailsDO();
            treeDetailsDO.setIsTree(0);
            treeDetailsMapper.update(treeDetailsDO, new EntityWrapper<TreeDetailsDO>().eq("id", detailsDO.getTreeDetailId()));
        }
        // 更改订单状态
        TreeOrderDO treeOrderDO = new TreeOrderDO();
        treeOrderDO.setStatus(OrderStatusType.CANCELED_SYS.getCode());
        treeOrderMapper.update(treeOrderDO,new EntityWrapper<TreeOrderDO>().eq("order_no",orderNo));
        return "ok";
     }

    @Override
    public TreeOrderDO detail(Long id, Long adminId) throws ServiceException {
        return treeOrderMapper.selectById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String customRefund(String orderNo, Integer sum, Long adminId) throws ServiceException {
        if (lockComponent.tryLock(ORDER_REFUND_LOCK + orderNo, 30)) {
            try {
                TreeOrderDO orderDO = treeBizService.checkOrderExist(orderNo, null);
                if (orderDO.getPayPrice() < sum || orderDO.getPayPrice() < (sum + orderDO.getRefundPrice())) {
                    throw new AdminServiceException(ExceptionDefinition.ORDER_REFUND_SUM_MOST_LOWER_THAN_PAY_PRICE);
                }
                if (orderDO.getStatus() != OrderStatusType.COMPLETE.getCode()) {
                    throw new AdminServiceException(ExceptionDefinition.ORDER_STATUS_NOT_SUPPORT_REFUND);
                }
                UserDO userDO = userMapper.selectById(orderDO.getUserId());
                Integer loginType = userDO.getLoginType();
                WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
                wxPayRefundRequest.setAppid(loginType == UserLoginType.MP_WEIXIN.getCode() ? wxMiNiAppid : wxAppAppid);
                wxPayRefundRequest.setOutTradeNo(orderNo);
                wxPayRefundRequest.setOutRefundNo("custom_refund_" + orderNo + System.currentTimeMillis());
                wxPayRefundRequest.setTotalFee(orderDO.getPayPrice());
                wxPayRefundRequest.setRefundFee(sum);
                // 记录退款金额
                treeOrderMapper.incRefundPrice(sum, orderDO.getId());
                if(orderDO.getPayPrice() == (sum + orderDO.getRefundPrice())){
                    TreeOrderDO updateOrderDO = new TreeOrderDO();
                    updateOrderDO.setStatus(OrderStatusType.REFUNDED.getCode());
                    updateOrderDO.setGmtUpdate(new Date());
                    treeBizService.changeOrderStatus(orderNo, OrderStatusType.COMPLETE.getCode(), updateOrderDO);
                }
                WxPayRefundResult wxPayRefundResult = wxPayService.refund(wxPayRefundRequest);
                if (!wxPayRefundResult.getReturnCode().equals("SUCCESS")) {
                    logger.warn("[微信退款] 失败 : " + wxPayRefundResult.getReturnMsg());
                    throw new AdminServiceException(wxPayRefundResult.getReturnMsg(),
                            ExceptionDefinition.THIRD_PART_SERVICE_EXCEPTION.getCode());
                }
                if (!wxPayRefundResult.getResultCode().equals("SUCCESS")) {
                    logger.warn("[微信退款] 失败 : " + wxPayRefundResult.getReturnMsg());
                    throw new AdminServiceException(wxPayRefundResult.getReturnMsg(),
                            ExceptionDefinition.THIRD_PART_SERVICE_EXCEPTION.getCode());
                }
                return "ok";
            } catch (ServiceException e) {
                throw e;
            } catch (WxPayException e) {
                logger.error("[微信退款] 异常", e);
                throw new AdminServiceException(StringUtils.isEmpty(e.getErrCodeDes()) ? e.getReturnMsg() : e.getErrCodeDes(),
                        ExceptionDefinition.THIRD_PART_SERVICE_EXCEPTION.getCode());
            } catch (Exception e) {
                logger.error("[微信退款] 异常", e);
                throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
            } finally {
                lockComponent.retree(ORDER_REFUND_LOCK + orderNo);
            }
        }
        throw new AdminServiceException(ExceptionDefinition.SYSTEM_BUSY);
    }

}
